/**
 * ********************************************************
 * <p>
 * Copyright (c) 2020 Baidu.com, Inc. All Rights Reserved
 * <p>
 * ********************************************************
 */
package com.baidu.mpks.util;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;

import java.io.IOException;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
public class JacksonUtil {
    private static final String DATE_PATTERN = "yyyy-MM-dd HH:mm:ss";
    private static JsonFactory JSON_FACTORY = new JsonFactory();
    private static ObjectMapper OBJECT_MAPPER = createObjectMapper();
    public static final String EMPTY_JSON = "{}";

    /**
     * 创建一个自定义的JSON ObjectMapper
     */
    private static ObjectMapper createObjectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setDateFormat(new SimpleDateFormat(DATE_PATTERN));
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.configure(SerializationFeature.INDENT_OUTPUT, false);
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        return objectMapper;
    }

    /**
     * 将对象转换为JSON字符串
     */
    public static <T> String toJson(T value) {
        if (value == null) {
            return EMPTY_JSON;
        }
        StringWriter sw = new StringWriter();
        JsonGenerator gen = null;
        try {
            gen = JSON_FACTORY.createGenerator(sw);
            OBJECT_MAPPER.writeValue(gen, value);
            return sw.toString();
        } catch (IOException e) {
            log.error("object to json exception!", e);
        } finally {
            if (gen != null) {
                try {
                    gen.close();
                } catch (IOException e) {
                    log.warn("Exception occurred when closing JSON generator!", e);
                }
            }
        }
        return EMPTY_JSON;
    }

    /**
     * 将字符串转成JsonNode
     */
    public static JsonNode toJsonNode(String value) {
        if (value == null) {
            return null;
        }
        try {
            return OBJECT_MAPPER.readTree(value);
        } catch (IOException e) {
            log.error("object to json exception!", e);
        }
        return null;
    }

    /**
     * 将一个JsonNode的某一个字段的值转成list
     *
     * @param node JsonNode对象
     * @param key  JsonNode的字段
     * @return List<String>
     */
    public static List<String> asList(JsonNode node, String key) {
        if (node == null) {
            return Arrays.asList("null");
        }
        List<String> list = new ArrayList<String>();
        JsonNode obj = node.get(key);
        if (obj == null) {
            return Arrays.asList("null");
        }
        if (obj.isArray()) {
            if (obj != null) {
                obj.forEach(x -> list.add(x.asText()));
            }
            return list;
        } else {
            return Arrays.asList(obj.asText());
        }
    }

    /**
     * 获取JsonNode里面的字符串，如果是数组返回第一个字符串，如果是字符串，返回字符串本身
     * JsonNode的value是Object的话会返回null
     *
     * @param node JsonNode对象
     * @param key  JsonNode的字段
     * @return String
     **/
    public static String getString(JsonNode node, String key) {
        if (node == null) {
            return "";
        }
        JsonNode obj = node.get(key);
        if (obj == null) {
            return "";
        }
        if (obj.isArray()) {
            if (obj != null && obj.size() > 0) {
                return obj.get(0).asText();
            }
            return "";
        } else {
            return obj.asText();
        }
    }

    /**
     * 根据key获取jsonNode对应的value
     * 如果jsonNode的value是个object而不是String则用这个
     *
     * @param jsonNode
     * @param key
     * @return
     */
    public static String getStringV2(JsonNode jsonNode, String key) {
        try {
            JsonNode jsonNode1 = jsonNode.get(key);
            if (jsonNode1 == null) {
                return null;
            }
            if (jsonNode1.isTextual()) {
                return jsonNode1.asText();
            }
            return OBJECT_MAPPER.writeValueAsString(jsonNode1);
        } catch (Exception e) {
            log.error("JsonNode get value  exception!", e);
            return null;
        }
    }


    /**
     * 获取JsonNode里面的第一个值
     *
     * @param node JsonNode对象
     * @param key  JsonNode的字段
     * @return
     */
    public static Object getObject(JsonNode node, String key) {
        if (node == null) {
            return null;
        }
        JsonNode obj = node.get(key);
        if (obj == null) {
            return null;
        }
        if (obj.isArray()) {
            if (obj != null && obj.size() > 0) {
                return obj.get(0);
            }
            return null;
        }
        return obj;
    }

    /**
     * 获取JsonNode里面的第一个节点
     *
     * @param node JsonNode对象
     * @param key  JsonNode的字段
     * @return
     */
    public static JsonNode getNode(JsonNode node, String key) {
        if (node == null) {
            return null;
        }
        JsonNode obj = node.get(key);
        if (obj == null) {
            return null;
        }
        if (obj.isArray()) {
            if (obj != null && obj.size() > 0) {
                return obj.get(0);
            }
            return null;
        }
        return obj;
    }

    /**
     * 增加JsonNode节点
     *
     * @param node  JsonNode对象
     * @param key   新增字段key
     * @param value 新增字段value
     */
    public static JsonNode addNode(JsonNode node, String key, Object value) {
        Map<String, Object> map = new HashMap<>();
        map.put(key, value);
        return addNode(node, map);
    }

    /**
     * 增加JsonNode节点
     *
     * @param node JsonNode对象
     * @param map  新增字段key-value
     */
    public static JsonNode addNode(JsonNode node, Map<String, Object> map) {
        if (node != null && MapUtils.isNotEmpty(map)) {
            Map<String, Object> nodeMap = toMap(node);
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                nodeMap.put(entry.getKey(), entry.getValue());
            }
            try {
                return toJsonNode(OBJECT_MAPPER.writeValueAsString(nodeMap));
            } catch (JsonProcessingException e) {
                log.info("convert json is error, e---->" + e);
            }
        }
        return node;
    }

    /**
     * 合并两个json串，只增不减
     *
     * @param mainNode
     * @param updateNode
     * @return
     */
    public static JsonNode merge(JsonNode mainNode, JsonNode updateNode) {

        Iterator<String> fieldNames = updateNode.fieldNames();
        while (fieldNames.hasNext()) {

            String fieldName = fieldNames.next();
            JsonNode jsonNode = mainNode.get(fieldName);
            // if field exists and is an embedded object
            if (jsonNode != null && jsonNode.isObject()) {
                merge(jsonNode, updateNode.get(fieldName));
            } else {
                if (mainNode instanceof ObjectNode) {
                    // Overwrite field
                    JsonNode value = updateNode.get(fieldName);
                    ((ObjectNode) mainNode).put(fieldName, value);
                }
            }

        }

        return mainNode;
    }

    public static Map<String, Object> toMap(JsonNode node) {
        return OBJECT_MAPPER.convertValue(node, new TypeReference<Map<String, Object>>() {
        });
    }

    public static List<Object> toList(JsonNode node) {
        return OBJECT_MAPPER.convertValue(node, new TypeReference<List<Object>>() {
        });
    }

    /**
     * 将json转成Object
     *
     * @param in
     * @param type
     * @param <T>
     * @return
     */
    public static <T> T getObjectFromJson(String in, TypeReference<T> type) {
        try {
            return OBJECT_MAPPER.readValue(in, type);
        } catch (Exception e) {
            log.info("json convert object is error in---->{},e---->{}", in, e);
            return null;
        }
    }

    public static <T> T readValue(String in, Class<T> clazz) {
        try {
            return OBJECT_MAPPER.readValue(in, clazz);
        } catch (Exception e) {
            log.info("json convert object is error in---->{},e---->{}", in, e);
            return null;
        }
    }

    public static <T> T convertValue(Object object, Class<T> clazz) {
        return OBJECT_MAPPER.convertValue(object, clazz);
    }
}